{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# 在 Flask 中创建 url\r\n",
    "\r\n",
    "Flask 可以使用 Flask 包的 `url_for()` 函数生成 url。在模板和视图函数中硬编码(hardcoded) url 是一种糟糕的做法。\r\n",
    "假设，我们想要从 `/<id>/<post-title>/` 到 `/<id>/post/<post-title>/` 重新构造我们博客的 url。\r\n",
    "如果我们在模板和视图函数中有硬编码的 url，那么我们就必须手动访问每个模板和视图函数来进行更改。\r\n",
    "但是，使用 `url_for()` 函数可以在管理单元中完成这样的更改。\r\n",
    "\r\n",
    " `url_for()` 函数 接受 端点`endpoint` 并以字符串的形式返回 URL 。\r\n",
    " 回想一下， `endpoint` 指的是 URL 的唯一名称，大多数时候它是视图函数的名称。\r\n",
    " \r\n",
    " 此时，main3.py 包含一个 root (/)路由，定义如下:\r\n",
    "\r\n",
    "```python\r\n",
    "#...\r\n",
    "@app.route('/')\r\n",
    "def index():        \r\n",
    "    return render_template('index.html', name='Jerry')\r\n",
    "#...\r\n",
    "```\r\n",
    "\r\n",
    "生成根的URL可以通过调用`url_for()`函数:`url_for('index')`。输出结果是`'/'`。下面的shell会话演示如何在控制台中使用 url_for()。\r\n"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "source": [
    "#  注: jupyter notebook 运行这段后会显示每个中间变量的输出, 不然默认只显示最后一个变量的输出或者不显示.\r\n",
    "from IPython.core.interactiveshell import InteractiveShell\r\n",
    "InteractiveShell.ast_node_interactivity = \"all\"  "
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# from flask import Flask\r\n",
    "# app = Flask(__name__)"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "source": [
    "from main2 import app\r\n",
    "from flask import url_for\r\n",
    "with app.test_request_context('/api'): # /api is arbitrarily chosen. /API是任意选择的,无关紧要\r\n",
    "    url_for('index')"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'/'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "注意，我们首先创建了一个请求上下文`app.test_request_context`(从而隐式地创建应用程序上下文)。如果尝试在没有请求上下文的控制台中使用 url_for() 将导致错误。您可以在前几节中了解有关应用程序和请求上下文的更多信息。\r\n",
    "\r\n",
    "如果 `URL_for()` 无法创建 URL，它将引发 `BuildError` 异常。\r\n",
    "\r\n",
    "若要生成绝对 url，请将 _external = True 传递到 url_for() ，如下所示:"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "source": [
    "with app.test_request_context('/api'):\r\n",
    "    url_for('index', _external=True)"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'http://localhost/'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "与其在 `redirect()` 函数中硬编码 url，不如始终使用 url_For() 来生成 url。例如:"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "\r\n",
    "@app.route('/admin/')\r\n",
    "def admin():\r\n",
    "    if not loggedin:\r\n",
    "        print(url_for('login'))\r\n",
    "        return redirect(url_for('login'))  # if not logged in then redirect the user to the login page\r\n",
    "    return render_template('admin.html')"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "要为动态路由生成 url，需要将动态部分作为关键字参数传递。例如:"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "source": [
    "with app.test_request_context('/api'):\r\n",
    "    url_for('user_profile', user_id = 100)\r\n",
    "\r\n",
    "with app.test_request_context('/api'):\r\n",
    "    url_for('books', genre='biography')"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'/user/100/'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "'/books/biography/'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "传递给 `URL_for()` 函数的额外关键字参数数量将作为查询字符串附加到 URL。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "with app.test_request_context('/api'):\r\n",
    "    url_for('books', genre='biography', page=2, sort_by='date-published')"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "`url_for()` 是模板中为数不多的可用函数之一。要在模板中生成 url，只需调用双花括号`{{ ... }}`中的 url_for()\r\n",
    "\r\n",
    "```html\r\n",
    "<a href=\"{{ url_for('books', genre='biography') }}\">Books</a>\r\n",
    "```"
   ],
   "metadata": {}
  }
 ],
 "metadata": {
  "orig_nbformat": 4,
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}